//package com.tianji.promotion.service.impl;
//
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.tianji.common.exceptions.BadRequestException;
//import com.tianji.common.exceptions.BizIllegalException;
//import com.tianji.common.utils.StringUtils;
//import com.tianji.common.utils.UserContext;
//import com.tianji.promotion.domain.po.Coupon;
//import com.tianji.promotion.domain.po.ExchangeCode;
//import com.tianji.promotion.domain.po.UserCoupon;
//import com.tianji.promotion.enums.CouponStatus;
//import com.tianji.promotion.enums.ExchangeCodeStatus;
//import com.tianji.promotion.mapper.CouponMapper;
//import com.tianji.promotion.mapper.UserCouponMapper;
//import com.tianji.promotion.service.IExchangeCodeService;
//import com.tianji.promotion.service.IUserCouponService;
//import com.tianji.promotion.utils.CodeUtil;
//import com.tianji.promotion.utils.RedisLock;
//import lombok.RequiredArgsConstructor;
//import org.springframework.aop.framework.AopContext;
//import org.springframework.data.redis.core.StringRedisTemplate;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import java.time.LocalDateTime;
//import java.util.concurrent.TimeUnit;
//
///**
// * <p>
// * 用户领取优惠券的记录，是真正使用的优惠券信息 服务实现类
// * </p>
// *
// * @author root
// * @since 2023-11-24
// */
//@Service
//@RequiredArgsConstructor
//public class UserCouponRedisServiceImpl extends ServiceImpl<UserCouponMapper, UserCoupon> implements IUserCouponService {
//
//    private final CouponMapper couponMapper;
//    private final IExchangeCodeService exchangeCodeService;
//    private final StringRedisTemplate redisTemplate;
//
//    //领取优惠券
//    @Override
//    public void receiveCoupon(Long id) {
//        // 1. 根据id查询优惠券相关信息  做校验
//        if(id == null){
//            throw new BadRequestException("非法参数");
//        }
//        Coupon coupon = couponMapper.selectById(id);
//        if(coupon == null){
//            throw new BadRequestException("优惠券不存在");
//        }
//        if(coupon.getStatus() != CouponStatus.ISSUING){
//            throw new BadRequestException("优惠券状态异常");
//        }
//        LocalDateTime now = LocalDateTime.now();
//        if (now.isBefore(coupon.getIssueBeginTime()) || now.isAfter(coupon.getIssueEndTime())) {
//            throw new BadRequestException("优惠券未开始或已过期");
//        }
//        if (coupon.getTotalNum() <= 0 || coupon.getIssueNum() >= coupon.getTotalNum()){
//            throw new BadRequestException("库存不足");
//        }
//        Long userId = UserContext.getUser();
//        //获取当前用户对该优惠券的已领数量
////        Integer count = this.lambdaQuery()
////                .eq(UserCoupon::getCouponId, id)
////                .eq(UserCoupon::getUserId, userId)
////                .count();
////        if(count != null && count >= coupon.getUserLimit()){
////            throw new BadRequestException("已达领取限额");
////        }
////        // 2. 优惠券已发放数量+1
////        couponMapper.incrIssueNum(id);
////        // 3. 生成用户券
////        saveUserCoupon(userId,coupon);
//
//        //Long类型 -128~127 之间是同一个对象  超过该区间是不同的对象
//        //Long.toString() 底层是 new String() 所以还是不同的对象
//        //Long.toString().intern()  intern() 方法是强制从常量池中取字符串
////        synchronized (userId.toString().intern()) {
////            // 从aop上下文中  获取当前类的代理对象
////            IUserCouponService userCouponServiceProxy = (IUserCouponService)AopContext.currentProxy();
////            userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon, null);//这种写法是调用代理对象的方法，该方法是有事务处理的
////        }
//        //通过工具类实现分布式锁
//        String key = "lock:coupon:uid:" + userId;
//        RedisLock redisLock = new RedisLock(key,redisTemplate);
//        boolean isLock = redisLock.tryLock(5, TimeUnit.SECONDS);
//        if(!isLock){
//            throw new BizIllegalException("操作太频繁了");
//        }
//        try {
//            //从aop上下文中 获取当前类的处理对象
//            IUserCouponService userCouponServiceProxy = (IUserCouponService)AopContext.currentProxy();
//            userCouponServiceProxy.checkAndCreateUserCoupon(userId, coupon, null);//这种写法是调用代理对象的方法，该方法是有事务处理的
//
//        }finally {
//            // 释放锁
//            redisLock.unlock();
//        }
//    }
//    //保存用户券
//    private void saveUserCoupon(Long userId, Coupon coupon) {
//        UserCoupon userCoupon = new UserCoupon();
//        userCoupon.setUserId(userId);
//        userCoupon.setCouponId(coupon.getId());
//        LocalDateTime termBeginTime = coupon.getTermBeginTime();// 优惠券使用开始时间
//        LocalDateTime termEndTime = coupon.getTermEndTime();// 优惠券使用截止时间
//        //这两个时间只可能同时为null 或者 都不是null,
//        // 如果同时为null,那么优惠券的有效期这个字段就不可能是null,优惠券的使用结束时间就是 当前时间 + 优惠券的有效期（天）
//        if (termBeginTime == null){
//            termBeginTime = LocalDateTime.now();
//            termEndTime = termBeginTime.plusDays(coupon.getTermDays());
//        }
//        userCoupon.setTermBeginTime(termBeginTime);
//        userCoupon.setTermEndTime(termEndTime);
//
//        // 保存
//        this.save(userCoupon);
//    }
//
//    @Override
//    @Transactional
//    public void exchangeCoupon(String code) {
//        // 1. 校验code是否为空
//        if(StringUtils.isBlank(code)){
//            throw new BadRequestException("非法参数");
//        }
//        // 2. 解析兑换码得到自增id
//        long serialNum = CodeUtil.parseCode(code);//自增id
//        // 3. 判断兑换码是否已兑换   采用redis的bitmap结构 setbit  key  offset  1   如果方法返回 true代表兑换码已兑换
//        boolean result = exchangeCodeService.updateExchangeCodeMark(serialNum,true);
//        if(result){
//            // 说明兑换码已经被兑换了
//            throw new BizIllegalException("兑换码已被使用");
//        }
//        try {
//            // 4. 判断兑换码是否存在 根据自增id 主键查询
//            ExchangeCode exchangeCode = exchangeCodeService.getById(serialNum);
//            if(exchangeCode == null){
//                throw new BizIllegalException("兑换码不存在");
//
//            }
//            // 5. 判断是否过期
//            LocalDateTime now = LocalDateTime.now();
//            LocalDateTime expiredTime = exchangeCode.getExpiredTime();
//            if(now.isAfter(expiredTime)){
//                throw new BizIllegalException("兑换码已过期");
//            }
//
//            // 6. 校验并生成用户券
//            Long userId = UserContext.getUser();
//            // 查询优惠券信息
//            Coupon coupon = couponMapper.selectById(exchangeCode.getExchangeTargetId());
//            if(coupon == null){
//                throw new BizIllegalException("优惠券不存在");
//            }
//            checkAndCreateUserCoupon(userId,coupon, serialNum);
//            // 7. 更新兑换码状态
//        }catch (Exception e){
//            // 将兑换码状态重置
//            exchangeCodeService.updateExchangeCodeMark(serialNum,false);
//            throw e;
//        }
//
//    }
//
//    @Override
//    @Transactional
//    public void checkAndCreateUserCoupon(Long userId, Coupon coupon, Long serialNum) {
//
////        synchronized (userId.toString().intern()){
//            //获取当前用户对该优惠券的已领数量
//            Integer count = this.lambdaQuery()
//                    .eq(UserCoupon::getCouponId, coupon.getId())
//                    .eq(UserCoupon::getUserId, userId)
//                    .count();
//            if(count != null && count >= coupon.getUserLimit()){
//                throw new BadRequestException("已达领取限额");
//            }
//            // 2. 优惠券已发放数量+1
//            couponMapper.incrIssueNum(coupon.getId());
//            // 3. 生成用户券
//            saveUserCoupon(userId,coupon);
//
//            if(serialNum != null){
//                // 修改兑换码的状态
//                exchangeCodeService.lambdaUpdate()
//                        .eq(ExchangeCode::getId,serialNum)
//                        .set(ExchangeCode::getStatus, ExchangeCodeStatus.USED)
//                        .set(ExchangeCode::getUserId,userId)
//                        .update();
//            }
////        }
//    }
//}
